package com.foreverwin.mes.meapi.utils;

import com.foreverwin.mes.core.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 下一编号工具类
 */
public class NextNumberUtil
{
    public static Logger logger = LoggerFactory.getLogger(NextNumberUtil.class);

    /**
     * 日期格式化
     * @param date
     * @param format
     * @return
     */
    public static String formatDate(Date date, String format)
    {
        SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
        Calendar calendar = Calendar.getInstance();

        calendar.setTime(date);
        calendar.setLenient(true);
        //calendar.setFirstDayOfWeek(dateService.getFirstDayOfWeek().getDayNumber() + 1);
        //calendar.setFirstDayOfWeek(calendar.getFirstDayOfWeek() + 1);//??????
        dateFormatter.setCalendar(calendar);
        String dateString = dateFormatter.format(calendar.getTime());

        int indexY = format.indexOf("y");
        int indexW = format.indexOf("w");

        if ((dateString != null) && (indexY != -1) && (indexW != -1)) {
            int weekOfYear = calendar.get(3);
            int month = calendar.get(2);
            int yearInt = calendar.get(1);
            if (month == 11)
            {
                if (weekOfYear == 1) {
                    yearInt++;
                    int indexLastY = format.lastIndexOf("y");

                    if ((indexY == indexLastY) || (indexLastY - indexY == 2)) {
                        indexLastY = indexY + 1;
                    }

                    dateString = replaceYear(dateString, indexY, indexLastY, yearInt);
                }
            }
        }
        return dateString;
    }

    /**
     * ISO 日期格式化
     * @param date
     * @param format
     * @return
     */
    public static String formatIsoDate(Date date, String format)
    {
        SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.setLenient(true);
        calendar.setFirstDayOfWeek(2);
        calendar.setMinimalDaysInFirstWeek(4);
        dateFormatter.setCalendar(calendar);
        String dateString = dateFormatter.format(calendar.getTime());

        int indexY = format.indexOf("y");

        if ((indexY != -1) && (dateString != null)) {
            int isoYearInt = getIsoYear(calendar);

            if (Integer.valueOf(calendar.get(1)).compareTo(Integer.valueOf(isoYearInt)) != 0) {
                int indexLastY = format.lastIndexOf("y");

                if ((indexY == indexLastY) || (indexLastY - indexY == 2)) {
                    indexLastY = indexY + 1;
                }
                dateString = replaceYear(dateString, indexY, indexLastY, isoYearInt);
            }
        }
        return dateString;
    }


    private static String replaceYear(String dateString, int indexY, int indexLastY, int yearInt)
    {
        String formattedYear = dateString.substring(indexY, indexLastY + 1);
        String year = Integer.toString(yearInt);
        if ((formattedYear != null) && (year != null)) {
            if (formattedYear.length() > year.length())
            {
                year = StringUtils.leftPad(year, "0", formattedYear.length());
            }year = year.substring(year.length() - formattedYear.length());
            StringBuffer dateBuffer = new StringBuffer(dateString);
            dateBuffer.replace(indexY, indexLastY + 1, year);
            return dateBuffer.toString();
        }
        return dateString;
    }

    /**
     * 获取ISO年
     * @param calendar
     * @return
     */
    public static int getIsoYear(Calendar calendar) {
        int isoWeekOfYear = calendar.get(3);
        int isoMonth = calendar.get(2);
        int isoYearInt = calendar.get(1);
        if (isoMonth == 0)
        {
            if (isoWeekOfYear >= 52) {
                isoYearInt--;
            }

        }
        else if (isoWeekOfYear == 1) {
            isoYearInt++;
        }

        return isoYearInt;
    }

    /**
     * 替换编号中所有参数
     * @param data
     * @param row
     * @param recursive
     * @param set
     * @return
     */
    private static String replaceParameterAll(Map<String, Object> data, int row, boolean recursive, HashSet set) {
        if ((data == null) || (row < 0) || (data.size() <= row)) {
            return "";
        }
        if ((recursive) && (set == null)) {
            set = new HashSet();
        }
        if (recursive) {
            set.add(data);
        }

        String retVal = null;
        StringBuffer tmpRetVal = new StringBuffer();
        boolean hasPrevious = false;
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            if (hasPrevious) {
                tmpRetVal.append("; ");
            }
            String att = entry.getKey();
            Object val = entry.getValue();
            tmpRetVal.append(att);
            tmpRetVal.append("=");
            if (val == null) {
                tmpRetVal.append("NULL");
            } else if ((val instanceof Map)) {
                if ((recursive) && (!set.contains(val))) {
                    set.add(val);
                    Map subData = (Map<String, Object>) val;

                    int n = subData.size();
                    tmpRetVal.append("{ ");
                    for (int i = 0; i < n; i++) {
                        tmpRetVal.append("{" + i + ": ");
                        tmpRetVal.append(replaceParameterAll(subData, i, true, set));
                        tmpRetVal.append("}");
                    }
                    tmpRetVal.append(" }");
                } else {
                    tmpRetVal.append("DATA");
                }
            } else {
                tmpRetVal.append("'");
                if ((val instanceof Date)) {
                    tmpRetVal.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) val));
                } else {
                    tmpRetVal.append(val.toString());
                }
                tmpRetVal.append("'");
            }
            hasPrevious = true;
        }
        retVal = tmpRetVal.toString();
        return retVal;
    }

    /**
     * 替换编号规则中的参数
     * @param data
     * @param s
     * @return
     * @throws UnsupportedOperationException
     */
    public static String replaceParameters(Map<String, Object> data, String s) throws UnsupportedOperationException {
        if ((s == null) || (data == null)) {
            return s;
        }

        String retVal = "";
        int loc = -1;
        int lastLoc = 0;
        int end = 0;
        boolean done = false;

        while (!done) {
            loc = s.indexOf(37, loc);//index of "%"
            if (loc < 0) {
                retVal = retVal + s.substring(lastLoc);
                done = true;
            } else {
                retVal = retVal + s.substring(lastLoc, loc);
                end = s.indexOf(37, loc + 1);
                if (end < 0) {
                    throw new UnsupportedOperationException("Mismatched Percent Signs in " + s);
                }

                String name = s.substring(loc + 1, end);

                if ((name != null) && (name.equals(""))) {
                    retVal = retVal + "%";
                    loc = end + 1;
                } else if ((name != null) && (name.equals(".ALL."))) {
                    loc = end + 1;
                    retVal = retVal + replaceParameterAll(data, 0, false, null);
                } else if ((name != null) && (name.equals(".ALLALL."))) {
                    loc = end + 1;
                    retVal = retVal + replaceParameterAll(data, 0, true, null);
                } else {
                    String val = null;
                    int dot = name.lastIndexOf(46);//.
                    int openBracket = name.lastIndexOf(91);//[
                    int closeBracket = name.lastIndexOf(93);//]

                    if ((openBracket > 0) && (openBracket < closeBracket) && (closeBracket < dot)) {//TEST[0].SITE
                        String rowStr = name.substring(openBracket + 1, closeBracket);

                        int row = 0;
                        try {
                            row = Integer.parseInt(rowStr);
                        } catch (NumberFormatException e) {
                            logger.debug("[Utils.java:803] number format exception, ignored" + e);
                        }
                        String subName = name.substring(dot + 1);
                        String dataName = name.substring(0, openBracket);
                        Object obj = data.get(dataName);
                        if ((obj instanceof List)) {
                            List<Map> subData = (List<Map>) obj;
                            if (row < subData.size()) {
                                Map<String, Object> map = subData.get(row);
                                val = (String) map.get(subName);
                            }
                        }
                    } else if (dot > 0) {
                        String refName = name.substring(0, dot);
                        String compName = name.substring(dot + 1);
                        if (compName.charAt(0) == '[') {//DATE_TIME.[
                            Object o = data.get(refName);
                            if ((o instanceof Date)) {
                                int pStart = compName.indexOf(91);
                                int pEnd = compName.indexOf(93);
                                if ((pEnd >= 0) && (pStart >= 0)) {
                                    String format = compName.substring(pStart + 1, pEnd);
                                    if (format != null) {
                                        Date d = (Date) o;
                                        if (refName.contains("ISO_DATE_TIME")) {
                                            val = NextNumberUtil.formatIsoDate(d, format);
                                        } else
                                            val = NextNumberUtil.formatDate(d, format);
                                    }
                                }
                            }
                        }
                    } else {
                        Object o = data.get(name);
                        if (((o instanceof Date)) && (o != null)) {
                            val = NextNumberUtil.formatDate((Date) o, "yyyy-MM-dd HH_mm_ss");
                        } else if (o != null) {
                            val = o.toString();
                        }
                    }
                    if (val == null) {
                        val = "%" + name + "%";
                    }

                    retVal = retVal + val;
                    loc = end + 1;
                }
            }

            lastLoc = loc;
        }

        return retVal;
    }

    /**
     * 按进制进行数字转换
     * @param number
     * @param base
     * @return
     */
    public static final String toStringWithBase(long number, int base)
    {
        String temp = RadixNumberUtil.format(number, base).toUpperCase(Locale.ENGLISH);

        StringBuffer sb = new StringBuffer();

        if (base != 34)
            return temp;
        for (int i = 0; i < temp.length(); i++) {
            char c = temp.charAt(i);
            if (c >= 'I') c = (char)(c + '\001');
            if (c >= 'O') c = (char)(c + '\001');
            sb.append(c);
        }
        return sb.toString();
    }
}
